// 5种hook常见方式   js注入
// Hook 中文译为钩子，Hook 实际上是 Windows 中提供的一种用以替换 DOS 下“中断”的系统机制，
// Hook 的概念在 Windows 桌面软件开发很常见，特别是各种事件触发的机制，在对特定的系统事件进行 Hook 后，
// 一旦发生已 Hook 事件，对该事件进行 Hook 的程序就会收到系统的通知，这时程序就能在第一时间对该事件做出响应。
// 在程序中将其理解为“劫持”可能会更好理解，我们可以通过 Hook 技术来劫持某个对象，
// 把某个对象的程序拉出来替换成我们自己改写的代码片段，修改参数或替换返回值，从而控制它与其他对象的交互。

// 1. js作为动态一种弱语言，直接将函数赋值即可覆盖原有逻辑，也是最简单的hook。
// 普通函数：
// window.alert("hello world")

// 装饰器或者猴子补丁
// window.alertMy = window.alert
// window.alert = function (s) {
//     console.log('Alert: ' + s);
//     if (true) { // 自定义判断条件
//         debugger
//         window.alertMy(s)
//     }
// }
// alert("hello world")
//
// parseMy = JSON.parse
// JSON.parse = function (s) {
//   console.log('JSON.parse: ' + s)
//   debugger
//   return parseMy(s)
// }
// JSON.parse('{"name": "zhangsan"}')

// 2. 对象的静态方法，可以当做普通函数进行hook。
// 对象的非静态方法，需要考虑上下文content，也就是对象的指针this。所以不能像普通函数一样直接赋值，
// 不过js提供了原型prototype模型，我们以localStorage.getItem为例
// var getItemMy = Storage.prototype.getItem
// Storage.prototype.getItem = (key) => {
//   console.log('Storage.prototype.getItem', key)
//   debugger
//   return getItemMy.call(localStorage, key)
// }
// localStorage.getItem('AEGIS_ID')


// 3.对于对象属性，js提供了方法Object.defineProperty，该方法可以拦截并修改对象属性。我们以document.domain为例，
// Object.defineProperty(document, 'domain', {
//     // 改为可修改属性！！！
//     configurable: true,
//     enumerable: true,
//     get: function() {
//         return this._domain || location.host;
//     },
//     set: function(value) {
//         this._domain = value;
//     }
// });


// 4.Proxy 对象用于创建一个对象的代理，从而实现基本操作的拦截和自定义（如属性查找、赋值、枚举、函数调用等）
// 。参考MDN：https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Proxy
// 由于Proxy是一个比较新的概念，所以只有高版本浏览器才支持该功能。
// const proxy1 = new Proxy(localStorage.getItem, {
//   // 1.目标对象
//   // 2.目标对象的上下文对象（this）
//   // 3.目标对象的参数数组
//   apply(target, object, args) {
//     console.log(target, object, args)
//     return target.call(object,...args);
//   }
// })
// // 需要将方法设置为
// localStorage.getItem = proxy1
// localStorage.getItem('AEGIS_ID')


// 5.批量hook示例
// js逆向过程，往往需要对各种关键函数进行hook，下面是找到的油猴脚本，直接复制后在控制台运行即可，
// 可以在变量var source中增加自己关注的函数进行监控。
// 以函数JSON.stringify为例，说明下面脚本流程。

// let item = source[i]; // 获取某项（字符串），即"JSON.stringify"
// let realCtx = getRealCtx(ctx, item); // 获取函数所在的对象（类），即JSON
// let realName = getRealName(item); // 获取函数名，即"stringify"
// let originFunc = realCtx[realName]; // 获取函数，即JSON.stringify
// hook(realCtx, realName, level, originFunc); // 执行hook，即将JSON.stringify赋值给自己定义的一个函数，内部调用originFunc实现原有逻辑

// ==UserScript==
// @name         HOOK ALL end
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  day day up!
// @author       FY
// @include      *
// @grant        none
// @run-at       document-end
// ==/UserScript==

(function () {
    'use strict';
    var source = ['DeCode', 'EnCode', 'decodeData', 'base64decode', 'md5', 'decode', 'btoa', 'MD5', 'RSA', 'AES', 'CryptoJS', 'encrypt', 'strdecode', "encode", 'decodeURIComponent', '_t', 'JSON.stringify', 'fromCharCode'];
    console.log("开始测试是否有解密函数");
    let realCtx, realName;

    function getRealCtx(ctx, funcName) {
        let parts = funcName.split(".");
        let realCtx = ctx;
        for (let i = 0; i < parts.length - 1; i++) {
            realCtx = realCtx[parts[i]];
        }
        return realCtx;
    }

    function getRealName(funcName) {
        let parts = funcName.split(".");
        return parts[parts.length - 1];
    }

    function hook(ctx, funcName, level, originFunc) {
        ctx[funcName] = function (a) {
            console.log("level:" + level + " function:" + funcName, a);
            console.log(originFunc.toString());
            console.log(originFunc.toString);
            debugger;
            return originFunc(a);
        };
    }

    function test(ctx, level) {
        for (let i = 0; i < source.length; i++) {
            let item = source[i];
            let realCtx = getRealCtx(ctx, item);
            let realName = getRealName(item);
            let originFunc = realCtx[realName];
            hook(realCtx, realName, level, originFunc);
        }
    }

    test(window, 1);
})();